package ru.ifmo.swing.genetics.monitoring.string;

import org.uncommons.watchmaker.framework.PopulationData;
import ru.ifmo.automaton.Automaton;
import ru.ifmo.automaton.SynchronizingAutomaton;
import ru.ifmo.common.Source;
import ru.ifmo.genetics.automaton.synchronizeable.fitness.StandartFitness;
import ru.ifmo.swing.InfoLabel;
import ru.ifmo.swing.Panel;
import ru.ifmo.swing.ProgressStartListener;
import ru.ifmo.swing.genetics.monitoring.common.SwingEvolutionObserver;

import javax.swing.*;

/**
 * @author avhaliullin
 */
public class StringInfoMonitor implements SwingEvolutionObserver<String>, ProgressStartListener {
    private Source<Automaton<Character, String>> automatonSource;
    private Automaton<Character, String> automaton;
    private int goodGenerationNumber;
    private int superGenerationNumber;
    private int minWordLength;
    private int minStatesCount;

    private final Panel view;
    private final InfoLabel realMswLength = new InfoLabel("m(A) = %s");
    private final InfoLabel candidateLength = new InfoLabel("|w| = %d");
    private final InfoLabel currentFitness = new InfoLabel("Fitness: %f");
    private final InfoLabel currentStatesCount = new InfoLabel("|Q.w| = %d");
    private final InfoLabel firstGoodGeneration = new InfoLabel("First generation with |Q.w| = %s is number %s");
    private final InfoLabel firstSuperGeneration = new InfoLabel("First generation with |Q.w| = %s and |w| = %s is number %s");

    public StringInfoMonitor(Source<Automaton<Character, String>> automatonSource) {
        this.automatonSource = automatonSource;
        view = new Panel();
        view.setHorizontal(false);
        view.add(realMswLength);
        view.add(candidateLength);
        view.add(currentFitness);
        view.add(currentStatesCount);
        view.add(firstGoodGeneration);
        view.add(firstSuperGeneration);
    }

    public JComponent getView() {
        return view;
    }

    public void populationUpdate(PopulationData<? extends String> populationData) {
        candidateLength.updateData(populationData.getBestCandidate().length());
        currentFitness.updateData(populationData.getBestCandidateFitness());
        int statesCount = automaton.getStatesCount() -
                StandartFitness.df(automaton, populationData.getBestCandidate());
        currentStatesCount.updateData(statesCount);
        if (statesCount < minStatesCount) {
            minStatesCount = statesCount;
            minWordLength = populationData.getBestCandidate().length();

            superGenerationNumber = populationData.getGenerationNumber();
            goodGenerationNumber = populationData.getGenerationNumber();

            firstGoodGeneration.updateData(minStatesCount, goodGenerationNumber);
            firstSuperGeneration.updateData(minStatesCount, minWordLength, superGenerationNumber);
        }

        if (statesCount == minStatesCount && populationData.getBestCandidate().length() < minWordLength) {
            superGenerationNumber = populationData.getGenerationNumber();
            minWordLength = populationData.getBestCandidate().length();
            firstSuperGeneration.updateData(minStatesCount, minWordLength, superGenerationNumber);
        }
    }

    public String getStringView() {
        StringBuilder sb = new StringBuilder();
        sb.append(realMswLength.getText()).append("\n");
        sb.append(candidateLength.getText()).append("\n");
        sb.append(currentFitness.getText()).append("\n");
        sb.append(currentStatesCount.getText()).append("\n");
        sb.append(firstGoodGeneration.getText()).append("\n");
        sb.append(firstSuperGeneration.getText()).append("\n");
        return sb.toString();
    }

    public int getGoodGenerationNumber() {
        return goodGenerationNumber;
    }

    public int getSuperGenerationNumber() {
        return superGenerationNumber;
    }

    public int getMinWordLength() {
        return minWordLength;
    }

    public int getMinStatesCount() {
        return minStatesCount;
    }

    public void progressStarted() {
        automaton = automatonSource.create();
        goodGenerationNumber = 1;
        superGenerationNumber = 1;
        minStatesCount = Integer.MAX_VALUE;
        minWordLength = Integer.MAX_VALUE;
        if (automaton instanceof SynchronizingAutomaton<?, ?>) {
            realMswLength.updateData(String.valueOf(((SynchronizingAutomaton<?, ?>) automaton).mswLength()));
        } else {
            realMswLength.updateData("-");
        }
    }
}
